package com.xhwl.centiotdata.suppliersystem.mili;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xhwl.centiotdata.pojo.constant.MiLiConstant;
import com.xhwl.centiotdata.pojo.dto.mili.LoginMiLiDTO;
import com.xhwl.centiotdata.ws.MyWebSocketClient;
import com.xhwl.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.security.MessageDigest;
import java.security.Security;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @description:
 * @author: wuyuhao
 * @createDate: 2022/10/11 13:44
 */
@Component
@Slf4j
public class GeneralMiLiHandler {

    public static Map<String, LoginMiLiDTO> userLogin = new HashMap<>();

    /**
     * 业务接口请求
     * @param user
     * @param ipAndPort
     * @param url
     * @param request
     * @return
     */
    public String doBusinessRequest(String user, LoginMiLiDTO login, String ipAndPort, String url, Object request) {
        String sign = login.getSign();
        String code = login.getCode();
        String timestamp = login.getTimestamp();

        // 生成密钥
        String secret = MD5(user + "Business" + timestamp + sign);

        // 加密发送的数据
        String encrypt = encrypt(request.toString(), secret);

        Object data = null;
        try {
            URI uri = new URI(ipAndPort + url + "?user=" + user + "&code=" + code);
            MyWebSocketClient client = new MyWebSocketClient(uri);
            client.connectBlocking();
            data = client.sendData(encrypt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 解密返回的数据
        return decrypt(data.toString(), secret);
    }

    public LoginMiLiDTO getLoginInfo(String user, String password, String ipAndPort) {
        // 判断当前用户在今天是否登陆过
        LoginMiLiDTO loginMiLiDTO = userLogin.get(user);
        if ((!ObjectUtils.isEmpty(loginMiLiDTO)) && isToday(Long.parseLong(loginMiLiDTO.getTimestamp()))) {
            return loginMiLiDTO;
        }
        String response = loginRequest(user, password, ipAndPort);
        JSONObject res = JSON.parseObject(response);
        if (res.getInteger("Result") != 0) {
            log.error("请求url: {}, errMsg: {}", MiLiConstant.LOGIN_URL, res.getString("Message"));
            throw new BusinessException(res.getString("Message"));
        }
        JSONObject body = res.getJSONObject("Body");
        log.info("登录信息: {}", body);
        // {"Body":{"Code":"029743e1bc814d91ae6672d270db38b5","Timestamp":"1666081640503","Sign":"9a0322c3-b2ed-4666-95f0-89fc56657223"},"Result":0,"Message":"操作成功"}
        return body.toJavaObject(LoginMiLiDTO.class);
    }

    private String loginRequest(String user, String password, String ipAndPort) {
        // 密码加密
        String verify = MD5(password);
        // 发送的数据组装
        JSONObject request = new JSONObject();
        request.put("User", user);
        request.put("Verify", verify);
        // 生成密钥
        String secret = MD5(user + "Authorization" + verify);
        // 发送的数据加密
        String encrypt = encrypt(request.toString(), secret);
        Object data = null;
        try {
            URI uri = new URI(ipAndPort + MiLiConstant.LOGIN_URL + "?user=" + user);
            MyWebSocketClient client = new MyWebSocketClient(uri);
            client.connectBlocking();
            data = client.sendData(encrypt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return decrypt(data.toString(), secret);
    }

    private boolean isToday(long timestamp) {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        //获取今天的日期
        String nowDay = sf.format(new Date());
        //对比的时间
        String day = sf.format(new Date(timestamp));
        return day.equals(nowDay);
    }

    public static String encrypt(String content, String password) {
        try {
            SecretKeySpec key = new SecretKeySpec(password.getBytes("UTF-8"), "AES");
            //新增加密算法提供者
            Security.addProvider(new BouncyCastleProvider());
            //创建一个密码对应，并指定提供者
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", BouncyCastleProvider.PROVIDER_NAME);
            String ivStr = password.substring(0, 16);
            IvParameterSpec iv = new IvParameterSpec(ivStr.getBytes("UTF-8"));
            cipher.init(Cipher.ENCRYPT_MODE, key, iv);
            byte[] byteContent = content.getBytes("utf-8");
            byte[] cryptography = cipher.doFinal(byteContent);
            return new String(Base64.getEncoder().encode(cryptography), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String decrypt(String text, String password) {
        try {
            byte[] cryptography = text.getBytes();
            SecretKeySpec key = new SecretKeySpec(password.getBytes("UTF-8"), "AES");
            //新增加密算法提供者
            Security.addProvider(new BouncyCastleProvider());
            //创建一个密码对应，并指定提供者
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", BouncyCastleProvider.PROVIDER_NAME);
            String ivStr = password.substring(0, 16);
            IvParameterSpec iv = new IvParameterSpec(ivStr.getBytes("UTF-8"));
            cipher.init(Cipher.DECRYPT_MODE, key, iv);
            byte[] content = cipher.doFinal(Base64.getDecoder().decode(cryptography));
            return new String(content, "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String MD5(String str) {
        char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                'a', 'b', 'c', 'd', 'e', 'f' };
        try {
            byte[] btInput = str.getBytes();
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            mdInst.update(btInput);
            byte[] md = mdInst.digest();
            int j = md.length;
            char[] strs = new char[j * 2];
            int k = 0;
            for (byte byte0 : md) {
                strs[k++] = hexDigits[byte0 >>> 4 & 0xf];
                strs[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(strs);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}
